'use client';

import { getLoadingControl } from '@/components/Loading';
import { showToast } from '@/components/Toast';
import { sleep } from '@/utils/common';
import { request } from '@/utils/front/request';
import { AxiosRequestConfig } from 'axios';
import { useCallback, useRef, useState } from 'react';

type ResData<T = Obj> = {
  data: T;
  message: string;
  success: boolean;
};

type Options = {
  silent?: boolean;
  isWaitTips?: boolean;
  isOpenLoading?: boolean;
  axiosOptions?: AxiosRequestConfig;
};

export function useHttp() {
  const [isLoading, setIsLoading] = useState<boolean>(false);

  const { openLoading, closeLoading } = getLoadingControl();

  const hideLoading = async (options: Options) => {
    await sleep(0.5);
    setIsLoading(false);
    options.isOpenLoading && closeLoading();
  };

  const showLoading = (options: Options) => {
    setIsLoading(true);
    options.isOpenLoading && openLoading();
  };

  const showTips = async <T = Obj>(options: Options, res: ResData<T>) => {
    if (options.silent) {
      return;
    }

    !options.isWaitTips
      ? showToast(res.message)
      : await new Promise(resolve =>
          showToast({
            message: res.message,
            duration: 2000,
            onClose: resolve,
          })
        );
  };

  const commonRef = useRef({
    hideLoading,
    showLoading,
    showTips,
  });

  const get = useCallback(
    async <T = Obj>(url: string, params = {}, options: Options = {}) => {
      commonRef.current.showLoading(options);

      try {
        const res = await request.get<ResData<T>, ResData<T>>(url, {
          params,
          ...(options.axiosOptions || {}),
        });

        await commonRef.current.hideLoading(options);
        commonRef.current.showTips(options, res);

        return res;
      } catch (err) {
        console.log('[useHttp]:', url, err);
        commonRef.current.hideLoading(options);
        return null;
      }
    },
    []
  );

  const post = useCallback(
    async <T = Obj>(url: string, data = {}, options: Options = {}) => {
      commonRef.current.showLoading(options);

      try {
        const res = await request.post<ResData<T>, ResData<T>>(url, data, {
          ...(options.axiosOptions || {}),
        });
        await commonRef.current.hideLoading(options);
        commonRef.current.showTips(options, res);

        return res;
      } catch (err) {
        console.log('[useHttp]:', url, err);
        commonRef.current.hideLoading(options);
        return null;
      }
    },
    []
  );

  const httpRef = useRef({
    get,
    post,
  });

  return { isLoading, http: httpRef.current };
}
